#include "AVIRecordQthread.h"

AVIRecordQthread::AVIRecordQthread(void)
{
	//Misc Vars
	recordstate=0;
	recordpaused=0;
	interruptkey = 0;
	tdata=0;
	initialtime=0;
	initcapture = 0;

	/////////////////////////////////////////////////////////
	//Variables/Options requiring interface
	/////////////////////////////////////////////////////////
	bits = 24; 

	//Video Options and Compressions
	timelapse=50;
	frames_per_second = 20;
	keyFramesEvery = 20;
	compquality = 10000;
	compfccHandler = mmioFOURCC('M', 'S', 'V', 'C');

	//Report variables
	nActualFrame=0;
	nCurrFrame=0;
	fRate=0.0;
	fActualRate=0.0;
	fTimeLength=0.0;
	nColors=24;
	strCodec = "Default Compressor"; 
	actualwidth=0;
	actualheight=0;

	pos_x = 0;
	pos_y = 0;
	areaWidth = 0;
	areaHieght = 0;
	filenamepath = "";
}

AVIRecordQthread::~AVIRecordQthread(void)
{
}

void AVIRecordQthread::run()
{
	RecordVideo(pos_y,pos_x,areaWidth,areaHieght,30,filenamepath.toStdString().c_str());
}
LPBITMAPINFOHEADER AVIRecordQthread::captureScreenFrame(int left,int top,int width, int height,int tempDisableRect)
{

	HDC hScreenDC = ::GetDC(NULL);

	HDC hMemDC = ::CreateCompatibleDC(hScreenDC);     
	HBITMAP hbm;

	hbm = CreateCompatibleBitmap(hScreenDC, width, height);
	HBITMAP oldbm = (HBITMAP) SelectObject(hMemDC, hbm);	 
	BitBlt(hMemDC, 0, 0, width, height, hScreenDC, left, top, SRCCOPY);	 	


	SelectObject(hMemDC,oldbm);    			
	LPBITMAPINFOHEADER pBM_HEADER = (LPBITMAPINFOHEADER)GlobalLock(Bitmap2Dib(hbm, bits));	

	if (pBM_HEADER == NULL) { 

		MessageBoxA(NULL,"Error reading a frame!","Error",MB_OK | MB_ICONEXCLAMATION);					
		exit(1);
	}    

	DeleteObject(hbm);			
	DeleteDC(hMemDC);	


	ReleaseDC(NULL,hScreenDC) ;	


	return pBM_HEADER;
}



int AVIRecordQthread::RecordVideo(int top,int left,int width,int height,int fps,const char *szFileName) {

	LPBITMAPINFOHEADER alpbi;
	AVISTREAMINFO strhdr;
	PAVIFILE pfile = NULL;
	PAVISTREAM ps = NULL, psCompressed = NULL;
	AVICOMPRESSOPTIONS opts;
	AVICOMPRESSOPTIONS FAR * aopts[1] = {&opts};
	HRESULT hr;
	WORD wVer;
	char szTitle[BUFSIZE];

	actualwidth=width;
	actualheight=height;	

	wVer = HIWORD(VideoForWindowsVersion());
	if (wVer < 0x010a){			 
		MessageBoxA(NULL, "Error! Video for Windows version too old!", "Error" , MB_OK|MB_ICONSTOP);
		return FALSE;
	}

	alpbi = NULL;

	////////////////////////////////////////////////
	// CAPTURE FIRST FRAME
	////////////////////////////////////////////////	
	alpbi=captureScreenFrame(left,top,width, height,1);


	////////////////////////////////////////////////
	// INIT AVI USING FIRST FRAME
	////////////////////////////////////////////////
	AVIFileInit();

	//
	// Open the movie file for writing....
	//
	strcpy(szTitle,"AVI Movie");

	hr = AVIFileOpen(&pfile, szFileName, OF_WRITE | OF_CREATE, NULL);	
	if (hr != AVIERR_OK) goto error;


	// Fill in the header for the video stream....
	// The video stream will run in 15ths of a second....
	_fmemset(&strhdr, 0, sizeof(strhdr));
	strhdr.fccType                = streamtypeVIDEO;// stream type

	//strhdr.fccHandler             = compfccHandler;
	strhdr.fccHandler             = 0;

	strhdr.dwScale                = 1;
	strhdr.dwRate                 = fps;		    
	strhdr.dwSuggestedBufferSize  = alpbi->biSizeImage;
	SetRect(&strhdr.rcFrame, 0, 0,		    // rectangle for stream
		(int) alpbi->biWidth,
		(int) alpbi->biHeight);

	// And create the stream;
	hr = AVIFileCreateStream(pfile,	&ps, &strhdr);
	if (hr != AVIERR_OK) 	goto error; 


	memset(&opts, 0, sizeof(opts)); 
	aopts[0]->fccType			 = streamtypeVIDEO;
	//aopts[0]->fccHandler		 = mmioFOURCC('M', 'S', 'V', 'C');
	aopts[0]->fccHandler		 = compfccHandler;
	aopts[0]->dwKeyFrameEvery	   = keyFramesEvery;		// keyframe rate 
	aopts[0]->dwQuality		 = compquality;        // compress quality 0-10,000 
	aopts[0]->dwBytesPerSecond	         = 0;		// bytes per second 
	aopts[0]->dwFlags			 = AVICOMPRESSF_VALID | AVICOMPRESSF_KEYFRAMES;    // flags 		
	aopts[0]->lpFormat			 = 0x0;                         // save format 
	aopts[0]->cbFormat			 = 0;
	aopts[0]->dwInterleaveEvery = 0;			// for non-video streams only 



	//The 1 here indicates only 1 stream
	//if (!AVISaveOptions(NULL, 0, 1, &ps, (LPAVICOMPRESSOPTIONS *) &aopts)) 
	//        goto error;


	hr = AVIMakeCompressedStream(&psCompressed, ps, &opts, NULL);
	if (hr != AVIERR_OK)  	goto error; 

	hr = AVIStreamSetFormat(psCompressed, 0, 
		alpbi,	    // stream format
		alpbi->biSize +   // format size
		alpbi->biClrUsed * sizeof(RGBQUAD));
	if (hr != AVIERR_OK) goto error;	


	FreeFrame(alpbi);	
	alpbi=NULL;


	DWORD timeexpended, frametime, oldframetime;		
	initialtime = timeGetTime();	
	initcapture = 1;	
	oldframetime = 0;

	nCurrFrame = 0;
	nActualFrame = 0;

	//////////////////////////////////////////////
	// WRITING FRAMES
	//////////////////////////////////////////////	

	long divx, oldsec;
	divx=0;
	oldsec=0;

	while (recordstate) 
	{  //repeatedly loop

		if (initcapture==0) {			 
			timeexpended = timeGetTime() - initialtime;
		}
		else {

			frametime = 0;
			timeexpended = 0;			

		}		


		alpbi=captureScreenFrame(left,top,width, height,0);		

		if (initcapture==0) {

			if (timelapse>1000)
				frametime++;
			else
				frametime = (DWORD) (((double) timeexpended /1000.0 ) * (double) (1000.0/timelapse));

		}
		else 
			initcapture = 0;

		fTimeLength = ((float) timeexpended) /((float) 1000.0);


		if ((frametime==0) || (frametime>oldframetime)) { 


			//if frametime repeats...the avistreamwrite will cause an error
			hr = AVIStreamWrite(psCompressed,	// stream pointer
				frametime,				// time of this frame
				1,				// number to write
				(LPBYTE) alpbi +		// pointer to data
				alpbi->biSize +
				alpbi->biClrUsed * sizeof(RGBQUAD),
				alpbi->biSizeImage,	// size of this frame
				//AVIIF_KEYFRAME,			 // flags....
				0,    //Dependent n previous frame, not key frame
				NULL,
				NULL);
			if (hr != AVIERR_OK)
				break;		

			nActualFrame ++ ;
			nCurrFrame = frametime;
			fRate = ((float) nCurrFrame)/fTimeLength;						
			fActualRate = ((float) nActualFrame)/fTimeLength;

			//Update recording stats every half a second
			divx = timeexpended / 500;

			if (divx != oldsec) {				
				oldsec=divx;
				//InvalidateRect(hWndGlobal,NULL, FALSE);				
			}			

			//free memory
			FreeFrame(alpbi);
			alpbi=NULL;

			oldframetime = frametime;


		} // if frametime is different



		//Version 1.1
		int haveslept = 0;
		int pausecounter = 0;
		int pauseremainder = 0;
		int pauseindicator = 1;
		DWORD timestartpause;
		DWORD timeendpause;
		DWORD timedurationpause;		
		while (recordpaused) {			

			if (!haveslept) timestartpause = timeGetTime();

			//Flash Pause Indicator in Title Bar
			pausecounter++;
			if ((pausecounter % 8)==0) { 

				//if after every 400 milliseconds (8 * 50)				
				if (pauseindicator) {
					//SetTitleBar("");
					pauseindicator = 0;
				}
				else {
					//SetTitleBar("Paused");
					pauseindicator = 1;
				}							

			}

			//do nothing.. wait
			::Sleep(50); //Sleep for 50 			

			haveslept=1;

		}

		//Version 1.1
		if (haveslept) {

			timeendpause = timeGetTime();
			timedurationpause =  timeendpause - timestartpause;

			//CString msgstr;
			//msgstr.Format("timestartpause %ld\ntimeendpause %ld\ntimedurationpause %ld",timeendpause,timeendpause,timedurationpause);
			//MessageBox(NULL,msgstr,"Note",MB_OK);

			initialtime = initialtime + timedurationpause;

		}
		else  {

			//introduce time lapse
			//maximum lapse when recordstate changes will be less than 100 milliseconds
			int no_iteration = timelapse/50;
			int remainlapse = timelapse - no_iteration*50;		 
			for (int j=0;j<no_iteration;j++)		
			{
				::Sleep(50); //Sleep for 50 milliseconds many times
				if (recordstate==0) break;
			}		
			if (recordstate==1) Sleep(remainlapse);

		}


	} //for loop


error:	

	AVISaveOptionsFree(1,(LPAVICOMPRESSOPTIONS FAR *) &aopts);	



	if (pfile)
		AVIFileClose(pfile);


	if (ps)
		AVIStreamClose(ps);


	if (psCompressed)
		AVIStreamClose(psCompressed);

	AVIFileExit();	


	return 0;
}



void AVIRecordQthread::setRectName(int x, int y,int w,int h,QString str)
{
	pos_x = x;
	pos_y = y;
	areaWidth  = w;
	areaHieght = h;
	filenamepath = str;
}